/* !
 * template.js v0.7.1 (https://github.com/yanhaijing/template.js)
 * API https://github.com/yanhaijing/template.js/blob/master/doc/api.md
 * Copyright 2015 yanhaijing. All Rights Reserved
 * Licensed under MIT (https://github.com/yanhaijing/template.js/blob/master/MIT-LICENSE.txt)
 */
/* eslint-disable */
;(function (root, factory) {
	var template = factory(root);
	if (typeof define === 'function' && define.amd) {
		// AMD
		define('template', function () {
			return template;
		});
	} else if (typeof exports === 'object') {
		// Node.js
		module.exports = template;
	} else {
		// Browser globals
		var _template = root.template;

		template.noConflict = function () {
			if (root.template === template) {
				root.template = _template;
			}

			return template;
		};
		root.template = template;
	}
}(this, function (root) {
	'use strict';
	var o = {
		sTag: '<%',//开始标签
		eTag: '%>',//结束标签
		compress: false,//是否压缩html
		escape: true, //默认输出是否进行HTML转义
		error: function (e) {
		}//错误回调
	};
	var functionMap = {}; //内部函数对象
	//修饰器前缀
	var modifierMap = {
		'': function (param) {
			return nothing(param)
		},
		'h': function (param) {
			return encodeHTML(param)
		},
		'u': function (param) {
			return encodeURI(param)
		}
	};

	var toString = {}.toString;
	var slice = [].slice;

	function type(x) {
		if (x === null) {
			return 'null';
		}

		var t = typeof x;

		if (t !== 'object') {
			return t;
		}

		var c = toString.call(x).slice(8, -1).toLowerCase();
		if (c !== 'object') {
			return c;
		}

		if (x.constructor == Object) {
			return c;
		}

		return 'unknown';
	}

	function isObject(obj) {
		return type(obj) === 'object';
	}

	function isFunction(fn) {
		return type(fn) === 'function';
	}

	function isString(str) {
		return type(str) === 'string';
	}

	function extend() {
		var target = arguments[0] || {};
		var arrs = slice.call(arguments, 1);
		var len = arrs.length;

		for (var i = 0; i < len; i++) {
			var arr = arrs[i];
			for (var name in arr) {
				target[name] = arr[name];
			}

		}
		return target;
	}

	function clone() {
		var args = slice.call(arguments);
		return extend.apply(null, [{}].concat(args));
	}

	function nothing(param) {
		return param;
	}

	function encodeHTML(source) {
		return String(source)
			.replace(/&/g, '&amp;')
			.replace(/</g, '&lt;')
			.replace(/>/g, '&gt;')
			.replace(/\\/g, '&#92;')
			.replace(/"/g, '&quot;')
			.replace(/'/g, '&#39;');
	}

	function compress(html) {
		return html.replace(/\s+/g, ' ').replace(/<!--[\w\W]*?-->/g, '');
	}

	function consoleAdapter(cmd, msg) {
		typeof console !== 'undefined' && console[cmd] && console[cmd](msg);
	}

	function handelError(e) {
		var message = 'template.js error\n\n';

		for (var key in e) {
			message += '<' + key + '>\n' + e[key] + '\n\n';
		}
		message += '<message>\n' + e.message + '\n\n';
		consoleAdapter('error', message);

		o.error(e);

		function error() {
			return 'template.js error';
		}

		error.toString = function () {
			return '__code__ = "template.js error"';
		}
		return error;
	}

	function parse(tpl, opt) {
		var code = '';
		var sTag = opt.sTag;
		var eTag = opt.eTag;
		var escape = opt.escape;

		function parsehtml(line) {
			// 单双引号转义，换行符替换为空格
			line = line.replace(/('|")/g, '\\$1');
			var lineList = line.split('\n');
			var code = '';
			for (var i = 0; i < lineList.length; i++) {
				code += ';__code__ += ("' + lineList[i] + (i === lineList.length - 1 ? '")\n' : '\\n")\n');
			}
			return code;
		}

		function parsejs(line) {
			//var reg = /^(:?)(.*?)=(.*)$/;
			var reg = /^(?:=|(:.*?)=)(.*)$/
			var html;
			var arr;
			var modifier;

			// = := :*=
			// :h=123 [':h=123', 'h', '123']
			if (arr = reg.exec(line)) {
				html = arr[2]; // 输出
				if (Boolean(arr[1])) {
					// :开头
					modifier = arr[1].slice(1);
				} else {
					// = 开头
					modifier = escape ? 'h' : '';
				}

				return ';__code__ += __modifierMap__["' + modifier + '"](typeof (' + html + ') !== "undefined" ? (' + html + ') : "")\n';
			}

			//原生js
			return ';' + line + '\n';
		}

		var tokens = tpl.split(sTag);

		for (var i = 0, len = tokens.length; i < len; i++) {
			var token = tokens[i].split(eTag);

			if (token.length === 1) {
				code += parsehtml(token[0]);
			} else {
				code += parsejs(token[0], true);
				if (token[1]) {
					code += parsehtml(token[1]);
				}
			}
		}
		return code;
	}

	function compiler(tpl, opt) {
		var mainCode = parse(tpl, opt);

		var headerCode = '\n' +
			'    var html = (function (__data__, __modifierMap__) {\n' +
			'        var __str__ = "", __code__ = "";\n' +
			'        for(var key in __data__) {\n' +
			'            __str__+=("var " + key + "=__data__[\'" + key + "\'];");\n' +
			'        }\n' +
			'        eval(__str__);\n\n';

		var footerCode = '\n' +
			'        ;return __code__;\n' +
			'    }(__data__, __modifierMap__));\n' +
			'    return html;\n';

		var code = headerCode + mainCode + footerCode;
		code = code.replace(/[\r]/g, ' '); // ie 7 8 会报错，不知道为什么
		try {
			var Render = new Function('__data__', '__modifierMap__', code);
			Render.toString = function () {
				return mainCode;
			}
			return Render;
		} catch (e) {
			e.temp = 'function anonymous(__data__, __modifierMap__) {' + code + '}';
			throw e;
		}
	}

	function compile(tpl, opt) {
		opt = clone(o, opt);

		try {
			var Render = compiler(tpl, opt);
		} catch (e) {
			e.name = 'CompileError';
			e.tpl = tpl;
			e.render = e.temp;
			delete e.temp;
			return handelError(e);
		}

		function render(data) {
			data = clone(functionMap, data);
			try {
				var html = Render(data, modifierMap);
				html = opt.compress ? compress(html) : html;
				return html;
			} catch (e) {
				e.name = 'RenderError';
				e.tpl = tpl;
				e.render = Render.toString();
				return handelError(e)();
			}
		}

		render.toString = function () {
			return Render.toString();
		};
		return render;
	}

	function template(tpl, data) {
		if (typeof tpl !== 'string') {
			return '';
		}

		var fn = compile(tpl);
		if (!isObject(data)) {
			return fn;
		}

		return fn(data);
	}

	template.config = function (option) {
		if (isObject(option)) {
			o = extend(o, option);
		}
		return clone(o);
	};

	template.registerFunction = function (name, fn) {
		if (!isString(name)) {
			return clone(functionMap);
		}
		if (!isFunction(fn)) {
			return functionMap[name];
		}

		return functionMap[name] = fn;
	}
	template.unregisterFunction = function (name) {
		if (!isString(name)) {
			return false;
		}
		delete functionMap[name];
		return true;
	}

	template.registerModifier = function (name, fn) {
		if (!isString(name)) {
			return clone(modifierMap);
		}
		if (!isFunction(fn)) {
			return modifierMap[name];
		}

		return modifierMap[name] = fn;
	}
	template.unregisterModifier = function (name) {
		if (!isString(name)) {
			return false;
		}
		delete modifierMap[name];
		return true;
	}

	template.__encodeHTML = encodeHTML;
	template.__compress = compress;
	template.__handelError = handelError;
	template.__compile = compile;
	template.version = '0.7.1';
	return template;
}));
